﻿#include "stdafx.h"

#include "CommLib.h"

void splitCString(CString str, CString delim, CStringArray &result)
{
	result.RemoveAll();
	int indexback = 0;
	CString st;
	int i;
	for(i = 0; i <str.GetLength(); i++)
	{
		if (str.GetAt(i) == delim.GetAt(0))
		{
			if ((i - indexback) == 0)
			{
				result.Add(_T(""));
			}
			else
			{
				st = str.Mid(indexback, i - indexback);
				result.Add(st);
			}
			indexback = i + 1;
		}
	}
	if ((i - indexback) != 0)
	{
		st = str.Mid(indexback, i - indexback);
		result.Add(st);
	}
}

BOOL IsIpAddress(CString strIp){

	strIp = strIp.Trim();
	if(strIp==""){
		return false;
	}

	CStringArray result;
	splitCString(strIp,_T("."),result);
	if(result.GetCount()!=4){
		return false;
	}
	else if(!result.GetAt(0).SpanExcluding(_T("0123456789")).IsEmpty() ||
		!result.GetAt(1).SpanExcluding(_T("0123456789")).IsEmpty() ||
		!result.GetAt(2).SpanExcluding(_T("0123456789")).IsEmpty() ||
		!result.GetAt(3).SpanExcluding(_T("0123456789")).IsEmpty()){
			return false;
	}
	else if(_tstoi(result.GetAt(0))>255 || _tstoi(result.GetAt(1))>255 ||
		_tstoi(result.GetAt(2))>255 || _tstoi(result.GetAt(3))>255){
			return false;
	}
	return true;
}

BOOL readIpFromFile(CString fileNm,CStringArray *IPArray)
{
	CStdioFile    stdFile;
	CString       wstr, rstr;
	LPTSTR        rstrBuf = NULL;
	int           err = 0;

	// (1)読み書き用にオープン
	if (!err)
	{
		if (!stdFile.Open(fileNm, 
			CFile::modeReadWrite | CFile::shareExclusive))
		{
			err = 1;
		}
	}

	if (!err)
	{
		TRY 
		{
			stdFile.SeekToBegin();
		}
		CATCH (CFileException, eP) 
		{
			err = 1;
		}
		END_CATCH
	}
	// (4)読み込み(CString)
	if (!err)
	{

		while (stdFile.ReadString(rstr) == TRUE)
		{
			//チェック
			if(IsIpAddress(rstr) == FALSE){
				err = 1;
				break;
			}
			IPArray->Add(rstr);
		}
	}

	stdFile.Close();
	return !err;
}

void FormatToStream(__in FILE * stream, __in DWORD fmt,...)

{
	va_list arglist;
	LPTSTR locbuffer = NULL;
	DWORD count;

	va_start(arglist, fmt);
	count = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ALLOCATE_BUFFER,
		NULL,
		fmt,
		0,              // LANGID
		(LPTSTR) &locbuffer,
		0,              // minimum size of buffer
		&arglist);

	if(locbuffer) {
		if(count) {
			int c;
			int back = 0;
			//
			// strip any trailing "\r\n"s and replace by a single "\n"
			//
			while(((c = *CharPrev(locbuffer,locbuffer+count)) == TEXT('\r')) ||
				(c == TEXT('\n'))) {
					count--;
					back++;
			}
			if(back) {
				locbuffer[count++] = TEXT('\n');
				locbuffer[count] = TEXT('\0');
			}
			//
			// now write to apropriate stream
			//
			_fputts(locbuffer,stream);
		}
		LocalFree(locbuffer);
	}
}

int UpdateCmd(__in LPCTSTR BaseName, __in LPCTSTR Machine, __in DWORD Flags, __in int argc, __in_ecount(argc) TCHAR* argv[])

{
	HMODULE newdevMod = NULL;
	int failcode = EXIT_FAIL;
	UpdateDriverForPlugAndPlayDevicesProto UpdateFn;
	BOOL reboot = FALSE;
	LPCTSTR hwid = NULL;
	LPCTSTR inf = NULL;
	DWORD flags = 0;
	DWORD res;
	TCHAR InfPath[MAX_PATH];

	UNREFERENCED_PARAMETER(BaseName);
	UNREFERENCED_PARAMETER(Flags);

	if(Machine) {
		//
		// must be local machine
		//
		return EXIT_USAGE;
	}
	if(argc<2) {
		//
		// at least HWID required
		//
		return EXIT_USAGE;
	}
	inf = argv[0];
	if(!inf[0]) {
		return EXIT_USAGE;
	}

	hwid = argv[1];
	if(!hwid[0]) {
		return EXIT_USAGE;
	}
	//
	// Inf must be a full pathname
	//
	res = GetFullPathName(inf,MAX_PATH,InfPath,NULL);
	if((res >= MAX_PATH) || (res == 0)) {
		//
		// inf pathname too long
		//
		return EXIT_FAIL;
	}
	if(GetFileAttributes(InfPath)==(DWORD)(-1)) {
		//
		// inf doesn't exist
		//
		return EXIT_FAIL;
	}
	inf = InfPath;
	flags |= INSTALLFLAG_FORCE;

	newdevMod = LoadLibrary(TEXT("newdev.dll"));
	if(!newdevMod) {
		goto final;
	}
	UpdateFn = (UpdateDriverForPlugAndPlayDevicesProto)GetProcAddress(newdevMod,UPDATEDRIVERFORPLUGANDPLAYDEVICES);
	if(!UpdateFn)
	{
		goto final;
	}

	//FormatToStream(stdout,inf ? MSG_UPDATE_INF : MSG_UPDATE,hwid,inf);

	if(!UpdateFn(NULL,hwid,inf,flags,&reboot)) {
		goto final;
	}

	//FormatToStream(stdout,MSG_UPDATE_OK);

	failcode = reboot ? EXIT_REBOOT : EXIT_OK;

final:

	if(newdevMod) {
		FreeLibrary(newdevMod);
	}

	return failcode;
}

int InstallLkbkAdpt(__in LPCTSTR BaseName, __in LPCTSTR Machine, __in DWORD Flags, __in int argc, __in_ecount(argc) TCHAR* argv[])
{
	HDEVINFO DeviceInfoSet = INVALID_HANDLE_VALUE;
	SP_DEVINFO_DATA DeviceInfoData;
	GUID ClassGUID;
	TCHAR ClassName[MAX_CLASS_NAME_LEN];
	TCHAR hwIdList[LINE_LEN+4];
	TCHAR InfPath[MAX_PATH];
	int failcode = EXIT_FAIL;
	LPCTSTR hwid = NULL;
	LPCTSTR inf = NULL;

	if(Machine) {

		return EXIT_USAGE;
	}
	if(argc<2) {

		return EXIT_USAGE;
	}
	inf = argv[0];
	if(!inf[0]) {
		return EXIT_USAGE;
	}

	hwid = argv[1];
	if(!hwid[0]) {
		return EXIT_USAGE;
	}
	if(GetFullPathName(inf,MAX_PATH,InfPath,NULL) >= MAX_PATH) {
		return EXIT_FAIL;
	}
	ZeroMemory(hwIdList,sizeof(hwIdList));
	if (FAILED(StringCchCopy(hwIdList,LINE_LEN,hwid))) {
		goto final;
	}
	if (!SetupDiGetINFClass(InfPath,&ClassGUID,ClassName,sizeof(ClassName)/sizeof(ClassName[0]),0))
	{
		goto final;
	}
	DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID,0);
	if(DeviceInfoSet == INVALID_HANDLE_VALUE)
	{
		goto final;
	}
	DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	if (!SetupDiCreateDeviceInfo(DeviceInfoSet,
		ClassName,
		&ClassGUID,
		NULL,
		0,
		DICD_GENERATE_ID,
		&DeviceInfoData))
	{
		goto final;
	}
	if(!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
		&DeviceInfoData,
		SPDRP_HARDWAREID,
		(LPBYTE)hwIdList,
		(lstrlen(hwIdList)+1+1)*sizeof(TCHAR)))
	{
		goto final;
	}
	//
	if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE,
		DeviceInfoSet,
		&DeviceInfoData))
	{
		goto final;
	}
	failcode = UpdateCmd(BaseName,Machine,Flags,argc,argv);

final:

	if (DeviceInfoSet != INVALID_HANDLE_VALUE) {
		SetupDiDestroyDeviceInfoList(DeviceInfoSet);
	}

	return failcode;
}

BOOL ExecCommandLine(CString cmdLine){

	STARTUPINFO si = {0};

	PROCESS_INFORMATION pi = {0};

	si.cb = sizeof(STARTUPINFO);
	si.lpReserved = NULL;
	si.lpReserved2 = NULL;
	si.cbReserved2 = 0;
	si.lpDesktop = NULL;
	si.dwFlags = 0;
	si.wShowWindow = SW_HIDE;
	si.dwFlags = STARTF_USESHOWWINDOW;

	int length = 1024;

	LPWSTR pwsz = cmdLine.GetBuffer(length);

	cmdLine.ReleaseBuffer();


	CreateProcess( NULL,
		pwsz,
		NULL,
		NULL,
		TRUE,
		NORMAL_PRIORITY_CLASS,
		NULL,
		NULL,
		&si,
		&pi );
	WaitForSingleObject( pi.hProcess, INFINITE );
	return TRUE;

}

// レジストリに文字値を設定
bool setRegValue(HKEY hKeyParent, LPCWSTR sKeyName, LPCWSTR sValueName, TCHAR  *sValue)
{
	DWORD dwOptions = REG_OPTION_NON_VOLATILE;
	REGSAM samDesired = KEY_ALL_ACCESS;
	LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
	HKEY hkResult;
	DWORD dwDisposition;
	if(RegCreateKeyEx(hKeyParent,
		sKeyName,
		0,
		(LPTSTR)sKeyName,
		dwOptions,
		samDesired,
		lpSecurityAttributes,
		&hkResult,
		&dwDisposition) != ERROR_SUCCESS){
			return false;
	}
	if(RegSetValueEx(hkResult,
		sValueName,
		0,
		REG_SZ,
		(const BYTE*)sValue,
		(lstrlen(sValue) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS){
			return false;
	}
	RegCloseKey(hkResult);
	return true;
}

BOOL HasLookAdapter(char*  pszDottedInetAddr)
{

	DWORD dwSize = 0;
	DWORD dwRetVal = 0;

	ULONG flags = GAA_FLAG_INCLUDE_PREFIX;

	ULONG family = AF_INET;

	LPVOID lpMsgBuf = NULL;

	unsigned int duplicateFlg = 0;

	PIP_ADAPTER_ADDRESSES pAddresses = NULL;
	ULONG outBufLen = 0;
	ULONG Iterations = 0;

	OSVERSIONINFOEX osver;
	ZeroMemory(&osver, sizeof(osver));
	osver.dwOSVersionInfoSize=sizeof(osver);
	GetVersionEx((OSVERSIONINFO*)&osver);


	outBufLen = WORKING_BUFFER_SIZE;

	do {

		pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
		if (pAddresses == NULL) {
			printf
				("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
			exit(1);
		}

		dwRetVal =
			GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);

		if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
			FREE(pAddresses);
			pAddresses = NULL;
		} else {
			break;
		}

		Iterations++;

	} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));


	WSADATA data;
   ZeroMemory(&data, sizeof(data));
   WSAStartup(MAKEWORD(2, 2), &data);

   
   if (dwRetVal == NO_ERROR) {
	   CString cmd;
	   WCHAR  *LoopBack = TEXT("Microsoft Loopback Adapter"); 
	   // adpts 配列内の各アダプタ情報を一つずつ adpt に入れてみていきます。
	   for(PIP_ADAPTER_ADDRESSES adpt = pAddresses; adpt; adpt = adpt->Next){
		   if(adpt->PhysicalAddressLength == 0)
		   {
			   continue;            // データリンク層を持たないなら
		   }
		   if(adpt->IfType == IF_TYPE_SOFTWARE_LOOPBACK){ 
			   continue;   // ループバック アドレスなら
		   }
		   if(wcsncmp(adpt->Description,LoopBack,26)!=0){
			   continue;
		   }
		   // adpt アダプタ情報の IP アドレスを一つずつ uni に入れてみていきます。
		   for(PIP_ADAPTER_UNICAST_ADDRESS uni = adpt->FirstUnicastAddress; uni; uni = uni->Next){
			   // DNS に対して適切なアドレスでない（プライベートなど）ならば
			   //if(~(uni->Flags) & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE) continue;   // 次のアドレスへ
			   // アプリケーションが使うべきでないアドレスなら
			   if(uni->Flags & IP_ADAPTER_ADDRESS_TRANSIENT){ continue;         // 次のアドレスへ
			   }
			   char host[NI_MAXHOST + 1] = {'\0'};   // host に「0.0.0.0」形式の文字列を取得します。
			   if(getnameinfo(uni->Address.lpSockaddr, uni->Address.iSockaddrLength
				   , host, sizeof(host), 0, 0, NI_NUMERICHOST/*NI_NAMEREQD*/) == 0){
					   if(strcmp(host, pszDottedInetAddr)==0){
						   duplicateFlg = 1;
						   break;
					   }
			   }
		   }

		   if(duplicateFlg == 1){

			   for(PIP_ADAPTER_UNICAST_ADDRESS uni = adpt->FirstUnicastAddress; uni; uni = uni->Next){

				   if(uni->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
				   {
					   continue;         // 次のアドレスへ
				   }
				   char host[NI_MAXHOST + 1] = {'\0'}; 
				   if(getnameinfo(uni->Address.lpSockaddr, uni->Address.iSockaddrLength
					   , host, sizeof(host), 0, 0, NI_NUMERICHOST/*NI_NAMEREQD*/) == 0){
						 
							   cmd = "netsh interface ip delete address name=\"";
							   cmd+=pAddresses->FriendlyName;
							   cmd+="\"  addr=";
							   cmd+=host;

							   ExecCommandLine(cmd);
						 
				   }
			   }

			   return true;
		   }
	   }
	   WSACleanup();
	}
	//delete pAdapterInfoBkp;

	return false;
}

BOOL Protectself(char*  pszDottedInetAddr,CStringArray *ipAddrArray)
{
	DWORD dwSize = 0;
	DWORD dwRetVal = 0;

	unsigned int i = 0;

	ULONG flags = GAA_FLAG_INCLUDE_PREFIX;

	ULONG family = AF_INET;

	LPVOID lpMsgBuf = NULL;

	unsigned int duplicateFlg = 0;

	PIP_ADAPTER_ADDRESSES pAddresses = NULL;
	ULONG outBufLen = 0;
	ULONG Iterations = 0;

	PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
	PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
	PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
	PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
	IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
	IP_ADAPTER_PREFIX *pPrefix = NULL;

	OSVERSIONINFOEX osver;
	ZeroMemory(&osver, sizeof(osver));
	osver.dwOSVersionInfoSize=sizeof(osver);
	GetVersionEx((OSVERSIONINFO*)&osver);


	outBufLen = WORKING_BUFFER_SIZE;

	do {

		pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
		if (pAddresses == NULL) {
			printf
				("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
			exit(1);
		}

		dwRetVal =
			GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);

		if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
			FREE(pAddresses);
			pAddresses = NULL;
		} else {
			break;
		}

		Iterations++;

	} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));

	if (dwRetVal == NO_ERROR) {
		CString cmd;

		char *pCmd = new char[1000+1];
		memset(pCmd,0,sizeof(pCmd));
		int len =0;

		if(ipAddrArray != nullptr && !ipAddrArray->IsEmpty()){
			for (int i=0;i<ipAddrArray->GetCount();i++)
			{
				cmd = "netsh interface ip add address name=\"";
				cmd+=pAddresses->FriendlyName;
				cmd+="\"  addr=";
				cmd+=ipAddrArray->GetAt(i);
				if((osver.dwMajorVersion>5))
				{
					cmd+=" mask=255.255.255.255 ";
				}
				else{
					cmd+=" mask=255.255.255.252 ";
				}

				ExecCommandLine(cmd);
			}
		}


		cmd = "netsh interface ip add address name=\"";
		cmd+=pAddresses->FriendlyName;
		cmd+="\"  addr=";
		cmd+=pszDottedInetAddr;
		cmd+=" mask=255.255.255.0 ";

		ExecCommandLine(cmd);

		if((osver.dwMajorVersion>5))
		{
			cmd.Format(_T("netsh interface ip set dns \"%s\" static 127.0.0.1 primary"),pAddresses->FriendlyName);
			ExecCommandLine(cmd);
		}
		else{
			cmd = _T("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\");
			cmd+=pAddresses->AdapterName;
			CString key = _T("NameServer");
			TCHAR  pValue[] = _T("127.0.0.1");
			setRegValue(HKEY_LOCAL_MACHINE,cmd,key,pValue);
		}

	}
	//delete pAdapterInfoBkp;

	return true;
}

typedef BOOL (WINAPI* SET_PREFERRED_UI_LANGUAGES_PROTOTYPE) (DWORD, PCWSTR, PULONG);
SET_PREFERRED_UI_LANGUAGES_PROTOTYPE pLangProc=NULL;

void SetThreadLocalSettings(LANGID Language, LANGID SubLanguage)
{


	OSVERSIONINFOEX osver;
	ZeroMemory(&osver, sizeof(osver));
	osver.dwOSVersionInfoSize=sizeof(osver);
	GetVersionEx((OSVERSIONINFO*)&osver);

	if((osver.dwMajorVersion>5))
	{
		if(pLangProc==NULL)
			pLangProc=(SET_PREFERRED_UI_LANGUAGES_PROTOTYPE)GetProcAddress(LoadLibraryA("kernel32"), "SetProcessPreferredUILanguages");

		if(pLangProc)
		{ // vista or 2008
			BOOL bResult=FALSE;
			ULONG ulNumOfLangs=1;
			WCHAR wszLanguages[32];
			wsprintfW(wszLanguages, L"%04X%c", MAKELANGID(Language, SubLanguage), 0);

			bResult=pLangProc(0, NULL, &ulNumOfLangs);
			bResult=pLangProc(MUI_LANGUAGE_ID, wszLanguages, &ulNumOfLangs);
		}
		else
		{ // fallback for XP
			::SetThreadLocale(MAKELCID(MAKELANGID(Language, SubLanguage), SORT_DEFAULT));
		}
	}
	else
	{ //XP
		::SetThreadLocale(MAKELCID(MAKELANGID(Language, SubLanguage), SORT_DEFAULT));
	}


}